home *** CD-ROM | disk | FTP | other *** search
/ SuperHack / SuperHack CD.bin / CODING / MISC / MAG03.ZIP / MAG03.TXT < prev   
Encoding:
Text File  |  1995-10-27  |  48.7 KB  |  1,287 lines

  1. Spellcaster presents:
  2.  
  3.  
  4. TTTTTTTTTT HH      HH EEEEEEEEEE    MM      MM    AAAA     GGGGGGGGG
  5.     TT     HH      HH EE            MMM    MMM   AA  AA   GG
  6.     TT     HH      HH EE            MM M  M MM  AA    AA  GG  
  7.     TT     HHHHHHHHHH EEEEEE        MM  MM  MM  AAAAAAAA  GG   
  8.     TT     HH      HH EE            MM      MM  AA    AA  GG    GGGG
  9.     TT     HH      HH EE            MM      MM  AA    AA  GG      GG
  10.     TT     HH      HH EEEEEEEEEE    MM      MM  AA    AA   GGGGGGGG
  11.  
  12.                                                         Issue 3
  13.                                                         4-10-95
  14.  
  15.  
  16.  
  17. ■ Index
  18.  
  19.         1. Introduction
  20.           1.1. About the magazine
  21.           1.2. About the author
  22.           1.3. Distribution
  23.           1.4. Contribuitions
  24.           1.5. Hellos and greets
  25.         2. Resolution of your homework
  26.         3. Procedures and functions
  27.           3.1. What are they ?
  28.           3.2. How to use
  29.           3.3. Global and local variables
  30.           3.4. Parameters
  31.           3.5. Functions
  32.         4. Introduction to assembly
  33.           4.1. Segments and offsets
  34.           4.2. Registers
  35.           4.3. The stack
  36.           4.4. The flags
  37.           4.5. More about segments
  38.           4.6. Basic instructions
  39.         5. Graphics, part 2 : The palette
  40.           5.1. Introduction
  41.           5.2. What's the palette
  42.           5.3. How to set and get the palette ?
  43.           5.4. The retrace
  44.           5.5. Palette effects
  45.               5.5.1. Rotations
  46.               5.5.2. Fades
  47.               5.5.3. The static screen
  48.         6. Points of View
  49.         7. The adventures of Spellcaster, part 3.
  50.  
  51.  
  52. ■ Introduction
  53.  
  54.   ■ About the magazine
  55.  
  56.     So, we've finally reached issue 3... A small step to me, but a great step
  57.   to computerkind...
  58.     This issue is packed with information... We have the second part of our
  59.   mode 13h tutorial (dedicated to palettes), plus an article on procedures and
  60.   functions for the begginers out there, besides other stuff.
  61.     This issue also has a special bonus... You probably have noticed that when
  62.   you decompress 'The Mag', you don't get only this text file, but a lot of
  63.   other files... They are a part of a small demo I did in two days, especially
  64.   for the mag. To run the demo, type in 'CBLIND' at the DOS prompt. I made it
  65.   to acompany this week's mode 13h tutorial, to demonstrate the potencial of the
  66.   palette, and the wonderfull effects you can achieve with it, if you think for
  67.   a bit... The hardest thing to do in the demo was to think of the effects.
  68.   Coding them is easy (except the cross-fade). The effects will be explained in
  69.   the Graphics section of 'The Mag'.
  70.     This magazine is dedicated to all the programmers and would-be programmers
  71.   out there, to those who wish to learn how to program anything, from demos
  72.   to games, passing through utilities and all sort of thing your mind can
  73.   think of.
  74.  
  75.     When you read this magazine, I'll assume some things. First, I assume you
  76.   have Borland's Turbo Pascal, version 6 and upwards. I'll also think you have
  77.   a 80386 (or 386 for short; a 486 would be even better), a load of patience
  78.   and a sense of humor. This last is almost essencial, because I don't receive
  79.   any money for doing this, so I must have fun doing it. I will also take for
  80.   certain you have the 9th grade (or equivelent).
  81.  
  82.     As I stated above, this magazine will be made especially for those who don't
  83.   know where to get information, or want it all in the same place, and to those
  84.   who want to learn how to program, so I'll try to build knowledge, building up
  85.   your skills issue by issue. If you sometimes fail to grasp some concept, don't
  86.   despair; try to work it out.
  87.     That's what I did... Almost everything I know was learnt from painfull
  88.   experience. If you re-re-re-read the article, and still can't understand it,
  89.   just drop a line, by mail, or just plain forget it. Most of the things I 
  90.   try to teach here aren't linked to each other (unless I say so), so if you
  91.   don't understand something, skip it and go back to it some weeks later. It
  92.   should be clearer for you then. Likewise, if you see any terms or words you 
  93.   don't understand, follow the same measures as before.
  94.  
  95.     Ok, as I'm earing the Net gurus and other god-like creatures talking
  96.   already, I'm just going to explain why I use Pascal.
  97.   For starters, Pascal is a very good language, ideal for the beginner, like 
  98.   BASIC (yech!), but it's powerfull enough to make top-notch programms.
  99.   Also, I'll will be using assembly language in later issues, and Pascal makes
  100.   it so EASY to use. 
  101.   Finally, if you don't like my choice of language, you can stop whining. The
  102.   teory behind each article is very simple, and common with any of the main
  103.   languages (C, C++, Assembly - Yes, that's true... BASIC isn't a decent
  104.   language).
  105.  
  106.     Just one last thing... The final part of the magazine is a little story
  107.   made up by my distorted mind. It's just a little humor I like to write, and
  108.   it hasn't got nothing to do with programming (well, it has a little), but, 
  109.   as I said before, I just like to write it.
  110.  
  111.   ■ About the author
  112.  
  113.     Ok, so I'm a little egocentric, but tell me... If you had the trouble of 
  114.   writing hundreds of lines, wouldn't you like someone to know you, even by 
  115.   name ?
  116.  
  117.     My name is Diogo de Andrade, alias Spellcaster, and I'm the creator, 
  118.   editor and writer of this magazine. 
  119.     I live in a small town called Setúbal, just near Lisbon, the capital of
  120.   Portugal... If you don't know where it is, get an encyclopedia, and look for
  121.   Europe. Then, look for Spain. Next to it, there's Portugal, and Setúbal is in
  122.   the middle.
  123.  
  124.     I'm 18 years old, and I just made it in to the university (if you do want
  125.   to know, I'm in the Technical Institute of Lisbon, Portugal), so I'm not 
  126.   a God-Like creature, with dozens of years of practice (I only program by 
  127.   eight years now, and I started in a Spectrum, progressing later to an Amiga.
  128.   I only program in the PC for a year or so), with a mega-computer (I own a 
  129.   386SX, 16 Mhz), that wear glasses with lens that look like the bottom of a 
  130.   bottle (I use glasses, but only sometimes), that has his head bigger than a 
  131.   pumpkin (I have a normal sized head) and with an IQ of over 220 (mine is 
  132.   actually something like 180). I can program in C, C++, Pascal, Assembly 
  133.   and even BASIC (yech!).
  134.  
  135.     So, if I am a normal person, why do I spend time writing this ?
  136.   Well, because I have the insane urge to write thousands of words every now
  137.   and then, and while I'm at it, I may do something productive, like teaching
  138.   someone. I may be young, but I know a lot about computers (how humble I am;
  139.   I know, modesty isn't one of my qualities).
  140.  
  141.     Just one more thing, if you ever program anything, please send to me... I
  142.   would love to see some work you got, maybe I even could learn something with
  143.   it. Also, give me a greet in your program/game/demo... I love seeing my 
  144.   name.
  145.  
  146.   ■ Contributions
  147.  
  148.     I as I stated before, I'm not a God... I do make mistakes, and I don't 
  149.   have (always) the best way of doing things. So, if you think you've spotted
  150.   an error, or you have thought of a better way of doing things, let me know.
  151.   I'll be happy to receive anything, even if it is just mail saying 'Keep it 
  152.   up'. As all human beings, I need incentive.
  153.  
  154.     Also, if you do like to write, please do... Send in articles, they will be
  155.   welcome, and you will have the chance to see your names up in lights.
  156.     They can be about anything, for a review of a book or program that can
  157.   help a programmer, to a point of view or a moan.
  158.  
  159.     If anyone out there has a question or wants to see an article about 
  160.   something in particular, feel free to write... All letters will be answered,
  161.   provided you give me your address.
  162.  
  163.     I'm also trying to start a new demo/game/utility group, and I need all sort 
  164.   of people, from coders (sometimes, one isn't enough), musicians (I can 
  165.   compose, but I'm a bit limited), graphics artists (I can't draw nothing) and
  166.   spreaders... I mean, by a spreader, someone who spreads things, like this mag.
  167.   If you have a BBS and you want it to include this magazine, feel free to
  168.   write me...
  169.  
  170.     You can also contact me personally, if study on the IST (if you don't
  171.   know what the IST is, you don't study there). I'm the freshman with the 
  172.   black hair and dark-brown eyes... Yes, the one that is occupying one of
  173.   the X-terminals... I recommend you to contact me personally, if you can,
  174.   especially if you are a member of the opposite sex (I'm a man, for those
  175.   of you who are wondering).
  176.  
  177.     My adress is:
  178.                  Praceta Carlos Manito Torres, nº4/6ºC
  179.                  2900 Setúbal
  180.                  Portugal
  181.  
  182.     Email: dgan@rnl.ist.utl
  183.  
  184.  
  185.   ■ Hellos and greets
  186.  
  187.     I'll say hellos and thanks to all my friend, especially for those who put 
  188.   up with my constant whining (you know who you are).
  189.     Special greets go to Denthor from Asphyxia (for the excelent VGA trainers),
  190.   Draeden from VLA (for assembly tutorials), Joaquim Elder Guerreiro, alias
  191.   Dr.Shadow (Delta Team is still up), Alex "Darkfox" (thanks for letting me
  192.   use your BBS), Joäo Neves and Henrique Craveiro for sugestions, and all the
  193.   demo groups out there.
  194.     I also want to say hi to my idols (I know they don't read this, but...),
  195.   Chris Roberts, François Lionet, Archer MacLean, everybody at ID Software and
  196.   Apogee, Sierra On-Line, Lucas Arts and Team 17, for showing me what 
  197.   programming is all about.
  198.  
  199.  
  200.  
  201.  
  202. ■ Resolution of your homework
  203.  
  204.     In last issue, I chalenged you to make an improvement in the 'Maths'
  205.   program I gave in Issue 1. Well, here's one of the possible improvements.
  206.   This gives you the hability to choose the operation you want to execute.
  207.  
  208.   Program Maths(Input,Output);
  209.  
  210.   Var A,B:Integer;
  211.       C,OP:Integer;
  212.  
  213.   Begin
  214.        Writeln('The Maths Version 2.0');
  215.        writeln;
  216.        Writeln('1 - Add');
  217.        Writeln('2 - Subract');
  218.        Writeln('3 - Multiply');
  219.        Writeln('4 - Divide');
  220.        Writeln('5 - Remainder');
  221.        Writeln;
  222.        Write('Type in the number of the operation:');
  223.        Readln(OP);
  224.        Write('Type in number A : ');
  225.        Readln(A);
  226.        Write('Type in number B : ');
  227.        Readln(B);
  228.        If OP=1 Then C:=A+B;
  229.        If OP=2 Then C:=A-B;
  230.        If OP=3 Then C:=A*B;
  231.        If OP=4 Then C:=A Div B;
  232.        If OP=5 Then C:=A Mod B;
  233.        Writeln;
  234.        Writeln('The result is ',C);
  235.        Writeln;
  236.        Readln;
  237.   End.
  238.  
  239.     This is quite simple... Depending on what operation you type in, the
  240.   program executes the relevant calculation and prints out the result.
  241.     There is still room from improvement in the program, but I leave to you
  242.   decide what to do. You already know, if you have questions, mail them to me
  243.   and I will answear them, or by mail or by the magazine.
  244.  
  245.  
  246.  
  247. ■ Procedures and functions
  248.  
  249.     These are two of the more powerfull of Pascal's resources. These give you
  250.   the hability to create new commands and functions. They are almost identical
  251.   in the way they work, so I will explain deeply the procedure and then I will
  252.   pass to the function, teaching you the diferences.
  253.  
  254.   ■ What are they ?
  255.  
  256.     Think of procedures like new commands, defined by you to do whatever you
  257.   want. They are very usefull, as you will see. Let's say you have a program
  258.   that writes the string 'Ok !' lots of time, and you don't want to spend time
  259.   always writing "WRITELN('OK !')", what do you do? You use a procedure !!
  260.  
  261.   ■ How to use
  262.  
  263.     In the above example, you would do something like this: before the start of
  264.   the main program block, write this:
  265.  
  266.   Procedure Writeok;
  267.   Begin
  268.        Writeln('Ok !');
  269.   End;
  270.  
  271.     Then, everytime you would write "Writeok" in your program, the program would
  272.   write 'OK !' in the screen. Let's see a working example:
  273.  
  274.   Program Test_8;
  275.  
  276.   Procedure Writeok;
  277.   Begin
  278.        Writeln('Ok !');
  279.   End;
  280.  
  281.   Begin
  282.        Writeln('How are you ?');
  283.        Writeok;
  284.        Readln;
  285.   End.
  286.  
  287.     The above example is stupid, but it's just for you to get the picture.
  288.   Notice that you can do ANYTHING you want in a procedure, just like in the
  289.   main block. You can even call other procedures from it. A procedure is like
  290.   an independant program, with it's one set of instructions and variables...
  291.  
  292.   ■ Local and global variables
  293.  
  294.     The procedure can have it's own variables, independants from the main
  295.   program. Look at the next example:
  296.  
  297.   Program Test_9;
  298.  
  299.   Var B:Integer;
  300.  
  301.   Procedure Something;
  302.   Var B:Word;
  303.   Begin
  304.        B:=10;
  305.        Writeln('In the procedure, B=',B);
  306.   End;
  307.  
  308.   Begin
  309.        B:=5;
  310.        Something;
  311.        Writeln('In the main program, B=',B);
  312.        Readln;
  313.   End.
  314.  
  315.     See what I mean? The main program ignores the changes made to variable B
  316.   inside the procedure. The variable B of the procedure is diferent of variable
  317.   B in the main program.
  318.     So, you come to a new concept. The variables defined outside the procedures
  319.   are called GLOBAL VARIABLES, and those who are created inside of a procedure
  320.   are called LOCAL VARIABLES.
  321.     The diference between them is that global variables can be used in all
  322.   program, not just in the main block, but in all procedures and functions,
  323.   while local variables can only be used inside the place they are defined.
  324.  
  325.   ■ Parameters
  326.  
  327.     Imagine now that you wanted to make a procedure to do a complex calculation
  328.   between the numbers 5 and 7. You would now use something that is called
  329.   PARAMETERS. They are used like this:
  330.  
  331.   Procedure DoCalc(A,B:Integer);
  332.   Var C:Integer;
  333.   Begin
  334.        C:=A+B*B;
  335.        Writeln('The result is ',C);
  336.   End;
  337.  
  338.     Now, you called the procedure like this:
  339.  
  340.              DoCalc(5,7);
  341.  
  342.     This works like this. The var A would get the value 5, and var B would get
  343.   the value 7. Then, the procedure's main code would be executed and the result
  344.   would be printed to the screen.
  345.     A parameter can be anything, from a number to a string. You can even have
  346.   different types of parameters, like this:
  347.  
  348.   Procedure Print(X,Y:Byte;S:String);
  349.  
  350.     You just use a semi-colon between them.
  351.     I know this is a little confusing at first, because you're dealing with new
  352.   concepts, but after you master this, you will get a priceless resource.
  353.  
  354.   ■ Functions
  355.  
  356.     The function is defined in the same way as the procedure, except that you
  357.   use the keyword FUNCTION instead of the PROCEDURE keyword. They work the same
  358.   way, but they have a diference. The function returns a value. This can be a
  359.   number, a char or even a string. The sintax is a little diferent, because of
  360.   this:
  361.  
  362.   Function DoCalc(A,B:Integer):Integer;     { This defines function DoCalc, }
  363.                                             { that requires two integers as }
  364.                                             { parameters, and that returns  }
  365.                                             { and integer value }
  366.   Var C:Integer;                            { Defines local variable C      }
  367.   Begin
  368.        C:=A+B*B;                            { This executes the calculation }
  369.                                             { and places the result in C    }
  370.        DoCalc:=C;                           { This tells the function to    }
  371.                                             { return the value in C.        }
  372.   End;
  373.  
  374.     Do call this, you would do something like this:
  375.  
  376.        D:=DoCalc(5,7);       { D is a global variable, defined as an integer }
  377.        Writeln(D);
  378.  
  379.        or
  380.  
  381.        Writeln(DoCalc(5,7);  { This saves a variable }
  382.  
  383.     There isn't a rule for what to use, procedure or function. It depends on
  384.   the program you are making. You can mix them up, having a procedure that calls
  385.   a function or vice-versa. You can even call a procedure with a function as a
  386.   parameter.
  387.  
  388.     There's a lot I haven't told you about procedures and functions, but I will
  389.   leave that for a future issue. In next issue I will talk about loops and
  390.   cicles. These are an almost essencial part of a program.
  391.  
  392.  
  393.  
  394.  
  395. ■ Introduction to assembly
  396.  
  397.     Somebody requested me to do an article about assembly, so here it is. This
  398.   is a very simplistic view of it, but it should be enough to make you start
  399.   coding some simple routines in Pascal with assembly.
  400.     Don't forget that assembly language is very complicated, and only people
  401.   that had a previous programming experience with some kind of high-level
  402.   language should try to venture themselves in it.
  403.     In the previous issue I explained some simple concepts of assembler, things
  404.   like the what is the BIOS, interrupts and other things like that. I even
  405.   explained how Pascal works with assembly. In the first issue, I explained
  406.   what are bytes and bits and their relatives, so I will assume you already
  407.   know that. So, without further due, I will talk about...
  408.  
  409.   ■ Segments and offsets
  410.  
  411.     This is the more annoying and complicated thing on the PC. Back in the time
  412.   when dinossaurs ruled the Earth, the guys that designed the original 8088
  413.   thought that nobody would ever need to address more than a meg (short for
  414.   megabyte) of memory, so they decided to built a machine that couldn't access
  415.   more than one meg of memory. But, for addressing one meg of memory, there was
  416.   the need for a 20 bit number. Because this wasn't pratical, they've came up
  417.   with a 'brilliant' way to do it. They would use two 16 bit registers. I know
  418.   this adds up to a 32 bit number, but that's not the way it works. It works
  419.   like this:
  420.  
  421.   Segment        0010100010001001
  422.   Offset             0010101010100101
  423.  
  424.   20 bit adress: 00101011001100110101 !!!!
  425.  
  426.     Here you have it... Segments and offsets combine to produce an absolute
  427.   address of memory. The standart notation for the memory addresses is:
  428.  
  429.                          Segment:Offset
  430.  
  431.     So, if somebody says that somethings in the address 6F1A:3652, that means
  432.   that it is in the segment 6F1A (in hex, of course), offset 3652 (still in
  433.   hex). Think of segments and offsets like this. The segment is the number of
  434.   the page, and the offset is how far in the page the data is...
  435.     Now, that you know what segments and offsets are, I can move on to...
  436.  
  437.   ■ Registers
  438.  
  439.     Registers are a special kind of variables, that are available to the
  440.   processor. They perform various functions inside the CPU, and they are a very
  441.   important part of assembly language. A list of their names, alongside with
  442.   their uses follows:
  443.  
  444.         ■ AX
  445.  
  446.           AX (also called the accumulator) is a general purpose 16 bit register.
  447.           It can be acessed as a word, or as two bytes, using AL or AH (the low
  448.           and the high part).
  449.           Examples:
  450.                    AX=10  =>   AL=10
  451.                                AH=0
  452.  
  453.                    AX=256 =>   AL=1
  454.                                AH=1
  455.  
  456.           General rule, anything you do to AL or AH will influence AX, because
  457.           you're manipulating it's low and high bytes.
  458.           Before I forget: AX = AH * 256 + AL
  459.           Do you understand it ?
  460.           AX has some special uses. General rule it is the destination for
  461.           memory grabs and multiplications. It's also plays a big part in port
  462.           accessing.
  463.  
  464.         ■ BX (BH/BL)
  465.  
  466.           BX is just like AX... You can also access its lower and higher bytes.
  467.           BX's special use is usually as an offset register.
  468.  
  469.         ■ CX (CH/CL)
  470.  
  471.           CX is just like AX and BX.
  472.           It is used as a counter in loops.
  473.  
  474.         ■ DX (DH/DL)
  475.  
  476.           DX is like AX, BX and CX.
  477.           It is used as destination is calculations and as a port index.
  478.  
  479.         ■ DI
  480.  
  481.           DI is a index register, a 16 bit register that is used for offsets.
  482.           You can't access it's higher and lower bytes.
  483.  
  484.         ■ SI
  485.  
  486.           Same as DI, but usually DI is paired with the ES segment register,
  487.           while SI is paired with the DS register.
  488.  
  489.         ■ DS
  490.  
  491.           This is a segment register, and it usually points to the Data Segment.
  492.  
  493.         ■ ES
  494.  
  495.           This is a segment register, that points to the Extra Segment.
  496.  
  497.         ■ FS
  498.  
  499.           This is like ES, but it only exists in the 386+.
  500.  
  501.         ■ GS
  502.  
  503.           Same as FS.
  504.  
  505.         The next registers you SHOULDN'T mess, unless you want your computer to
  506.         crash.
  507.  
  508.         ■ BP
  509.  
  510.           Base pointer. This is an offset to use with the Stack Segment.
  511.  
  512.         ■ SP
  513.  
  514.           Stack pointer. This is an offset to use with the Stack Segment.
  515.  
  516.         ■ SS
  517.  
  518.           This is a segment register, that points to the Stack Segment.
  519.  
  520.         ■ CS
  521.  
  522.           This is a segment register, that points to the Code Segment.
  523.  
  524.         ■ IP
  525.  
  526.           This is the Intruction Pointer, that is used with CS.
  527.  
  528.  
  529.   ■ The stack
  530.  
  531.     The stack is a temporary storage place, where data doesn't stay for long.
  532.   It has the same principle of a stack of plates, except that the stack starts
  533.   in the roof. This follows the order first in, last out, so, you must take the
  534.   things in the reverse order that you put them in.
  535.     I know this is confusing, but after some examples, you will feal right at
  536.   home.
  537.  
  538.  
  539.   ■ The flags
  540.  
  541.     The flags are like status indicators. They have all sort of indications for
  542.   you to read and interpret. They only have the value true or false, and you
  543.   can't access them directly.
  544.     There are 17 flags, but you only have to know some of them:
  545.  
  546.         ■ Carry Flag (CF)
  547.  
  548.           The carry flag is used for many things. It's like a general purpose
  549.           flag. It is one of the more used flags.
  550.  
  551.         ■ Parity Flag (PF)
  552.  
  553.           This flag is active when the value returned from last operation is
  554.           even.
  555.  
  556.         ■ Zero Flag (ZF)
  557.  
  558.           This flag is set when the last operation returned a zero.
  559.  
  560.         ■ Overflow Flag (OF)
  561.  
  562.           This flag is set when the last operation went out of bounds.
  563.  
  564.     These are the ones mostly used. There are others, as stated before, but
  565.   they aren't very used.
  566.  
  567.   ■ More about segments
  568.  
  569.     In pure assembly, you can define the segmentation of your program, but has
  570.   we are using assembly with Pascal, we must use the Pascal's default
  571.   segmentation, that is called Dos Segmentation. This means that there are four
  572.   principal segments. There are addressed by CS, SS, DS, ES. They are called
  573.   Code Segment, Stack Segment, Data Segment and Extra Segment.
  574.  
  575.         ■ Code Segment
  576.  
  577.           This is where your program resides. You probably now already that a
  578.           segment can only have 64Kb of size, so you only get 64Kb for the code
  579.           of your program. Now figure out why is it dangerous to change the CS
  580.           register.
  581.           One more thing about the CS register. It pairs up with the IP register
  582.           to give the computer the address of the current instruction.
  583.  
  584.         ■ Stack Segment
  585.  
  586.           This is the place of the stack.
  587.  
  588.         ■ Data Segment
  589.  
  590.           This is where the data normally goes... It can go to other places,
  591.           using pointers, but that's another story.
  592.  
  593.         ■ Extra Segment
  594.  
  595.           An extra segment for data.
  596.  
  597.   ■ Basic instructions
  598.  
  599.     Next, it follows a list of the essencial assembly instructions, the ones
  600.     you should know from back to forth.
  601.  
  602.         ■ Mov
  603.  
  604.           This is the single more important instruction in Asm (short for
  605.           assembly). The sintax is:
  606.  
  607.                          Mov to,from
  608.  
  609.           The to and from parameters can be almost anything you want. Let's
  610.           show some examples:
  611.  
  612.           Mov AX,40         This puts the imediate value 40 in AX
  613.           Mov AL,20         This puts the imediate value 20 in AL
  614.           Mov DH,10         This puts the imediate value 10 in DH
  615.           Mov CX,BX         This puts what's in BX in CX
  616.           Mov AX,[DS:SI]    This puts the word that is at DS:SI in AX
  617.           Mov [ES:DI],BX    This puts what's in BX in ES:DI
  618.           Mov [ES:DI+5],CX  This puts what's in CX in ES:DI+5
  619.           Mov DX,[x]        This puts what's in var x in DX
  620.  
  621.           This is easy enough.
  622.  
  623.  
  624.         ■ Int
  625.  
  626.           I already talked about this command in last issue. This command calls
  627.           up an interrupt. Sintax:
  628.  
  629.                            Int n
  630.  
  631.           Examples:
  632.                            Int 10h      This calls interrupt 10 (in hex)
  633.                            Int 10       This calls interrupt 10 (in dec)
  634.  
  635.  
  636.         ■ Stosb
  637.  
  638.           This stores what's in AL in destination ES:DI, and then increments
  639.           DI by one. It hasn't got any parameters.
  640.  
  641.         ■ Stosw
  642.  
  643.           Just like Stosb, but is transfers whats in AX and increments Di by
  644.           two.
  645.  
  646.         ■ Movsb
  647.  
  648.           This moves the byte that is in DS:SI to ES:DI, and then increments
  649.           SI and DI by one.
  650.  
  651.         ■ Movsw
  652.  
  653.           This moves the word as DS:SI to ES:DI, and then increments SI and DI
  654.           by two.
  655.  
  656.         ■ Add
  657.  
  658.           Sintax:
  659.                         Add dest,source
  660.  
  661.           This adds source to dest and stores the result in dest. Dest can't be
  662.           and imediate value, as obvious.
  663.  
  664.         ■ Sub
  665.  
  666.           Sintax:
  667.                         Sub dest,source
  668.  
  669.           This subtracts source from dest and stores the result in dest.
  670.  
  671.         ■ Mul
  672.  
  673.           Sintax:
  674.                         Mul source
  675.  
  676.           This multiplies source by AX (if source is a word) or by AL (if
  677.           source is a byte). The result is stored in AX (if source is a byte)
  678.           or in DX:AX (if source is a word).
  679.  
  680.         ■ Push
  681.  
  682.           This pushes something onto the stack. The sintax is:
  683.  
  684.                         Push source
  685.  
  686.           Source can be a register or an immediate value.
  687.  
  688.         ■ Pop
  689.  
  690.           This takes off something off the stack. The sintax is:
  691.  
  692.                         Pop dest
  693.  
  694.           Dest is where you want to put the value you take.
  695.           Remember what I said about first in, last out ?
  696.           Take a look at these examples:
  697.  
  698.                Mov ax,5                 AX=5
  699.                Push ax                  Puts AX in the stack
  700.                Mov ax,10                AX=10
  701.                Pop ax                   Takes the last value put in the stack,
  702.                                         in this case, AX=5
  703.  
  704.                Mov ax,10
  705.                Mov bx,5
  706.                Push ax
  707.                Push bx       This piece of code would swap the values of AX and
  708.                Pop ax        BX. Because first in is the last out.
  709.                Pop bx
  710.  
  711.     So, that's about it... There's lots of other things, but this should cover
  712.     up the basic. Get some source codes and experiment with them. If you have
  713.     any doubts, drop me a line and I'll try to explain myself better. If you
  714.     want some source code, feel free to ask me some...
  715.  
  716.  
  717.  
  718. ■ Graphics, part II : Palettes
  719.  
  720.     ■ Introduction
  721.  
  722.       The palette is a mistery to most programmers, even professional ones, and
  723.     often overlooked as beeing not too important. But I'm of those who think
  724.     that the palette and effects derived from it have a great potencial. To see
  725.     what I'm saying, just execute the 'Color Blind' demo I made especially for
  726.     the magazine. I made it in a couple of days, and I think it's fairly good,
  727.     considering that it pratically just uses the palette.
  728.  
  729.     ■ What's the palette
  730.  
  731.       A palette is a place where colors are stored. Has you should already now,
  732.     the mode 13h palette has 256 colors. Each one has a number, ranging from 0
  733.     to 255, and an intensity value for each of it's components.
  734.       In the PC, as in real life, colors are the result of the mixture of
  735.     primary colors. You should have learned about it in the 5th grade. But, in
  736.     real life, the primary colors are blue, yellow, magenta, black and white.
  737.     In computerland, there are only three basic colors: red, green and blue.
  738.     Each one of them can be mixed together in diferent ammounts.
  739.       But (there's always a but everywhere), NEVER forget that two colors can
  740.     look just the same in the screen and be completely different. Also, don't
  741.     forget that when you alter the palette, all the pixels in the screen drawn
  742.     with that color will be changed. For example, imagine you just set color 53
  743.     and 80 with the same RGB (short for red,green and blue components), and
  744.     filled the screen with pixels color 53 and 80. Well, when you looked at the
  745.     screen, it would look like it was filled with the same color, but when you
  746.     changed color 80, the entire screen would change the look entirely.
  747.  
  748.     ■ How to set and get the palette
  749.  
  750.       This is easy. You just have to remember that everything concerning the
  751.     palette is done through the ports 3C7h, 3C8h and 3C8h.
  752.       So, let's get the palette of a specific color. All you have to do is to
  753.     enter the number of the color you want into port 3C7h and then read in the
  754.     values of the red, green and blue components from port 3C9h. For acessing
  755.     the ports, you use a Pascal defined array that is called PORT. It is
  756.     something like the MEM array. The sintax is:
  757.  
  758.                    Port[number of the port]
  759.  
  760.       So, a procedure to read in the RGB values of one color would be like
  761.     this:
  762.  
  763.       Procedure GetColor(Col:Byte;Var R,G,B:Byte);
  764.       Begin
  765.            Port[$3C7]:=Col;
  766.            R:=Port[$3C9];
  767.            G:=Port[$3C9];
  768.            B:=Port[$3C9];
  769.       End;
  770.  
  771.       To set the palette, it's almost the same... You put the number of the
  772.     color you want to change into port 3C8h and then put the values in port
  773.     3C9h, in the order red, green and blue. Remember that the intensity is a
  774.     number from 0 to 63.
  775.  
  776.       Procedure SetColor(Col,R,B,G:Byte);
  777.       Begin
  778.            Port[$3C8]:=Col;
  779.            Port[$3C9]:=R;
  780.            Port[$3C9]:=G;
  781.            Port[$3C9]:=B;
  782.       End;
  783.  
  784.       This is very easy, tough it has some quirks...
  785.       Now, let's go to something harder... Setting the whole palette !!
  786.       The way I do it is like this: first I define two records, one to store
  787.     the RGB value of one color and the other to store the whole palette.
  788.  
  789.       Type RgbItem=Record
  790.                          R,G,B:Byte;
  791.                    End;
  792.            RgbList=Array[0..255] of RgbItem;
  793.  
  794.       Then, you define the procedure to read the palette into a var of the
  795.     predefined type:
  796.  
  797.       Procedure GetPalette(Var Pal:RgbList);
  798.       Var A:Byte;
  799.       Begin
  800.            For A:=0 To 255 do GetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
  801.       End;
  802.  
  803.       You just get the colors of the 256 colors and store them into an array,
  804.     where you can change them at you will. To set the whole palette, just do
  805.     the same, like this:
  806.  
  807.       Procedure SetPalette(Pal:RgbList);
  808.       Var A:Byte;
  809.       Begin
  810.            For A:=0 To 255 do SetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
  811.       End;
  812.  
  813.       As you see, it's fairly easy... But, if you are brave, you'll probably
  814.     just went and tried the routines. If you do so, you will be disapointed with
  815.     the results. You'll probably get a screen full of "snow". The "Snow" is the
  816.     dots that appear in your screen when you change colors.
  817.  
  818.     ■ The retrace
  819.  
  820.       So, how can you stop this? First, you must understand something about
  821.     monitor theory. As you may already know, the image in your screen is updated
  822.     by an electron beam, that sweeps the screen, from left to right. When it
  823.     reaches the end of a line, it goes to another line. When it reaches the end
  824.     of the screen, the electron beam resets to it's initial position in the
  825.     upper left corner. This period, while the beam goes from the lower right
  826.     corner to the upper left one, is called the Vertical Retrace, or Vertical
  827.     Blank. How is this helpfull? Well, during this period, anything you do to
  828.     the screen won't show imediatly, so, you can change the palette, draw
  829.     sprites, or anything else, and it would only show in the next retrace. But,
  830.     everything has a downside, and the VBL (Vertical BLank) is no exception. The
  831.     period is very, very short. So that you'll know, it occurs a VBL almost 70
  832.     times a second, so, anything you want to do you'll have to do it fast... You
  833.     should use frequenty the retrace, especially when you do lot's of thing on
  834.     the screen.
  835.       But this is enough for setting the whole palette without fuzz. The
  836.     following procedure waits first for the retrace to begin. It is all in
  837.     assembler, and it's quite complicated. To the tech-minded out there, we
  838.     simply get a byte from port 3DAh. If the third bit of the byte is set,
  839.     that means that VBL in occuring.
  840.  
  841.       Procedure WaitVBL; Assembler;
  842.       Label A1,A2;
  843.       Asm
  844.          Mov DX,3DAh
  845.       A1:
  846.          In AL,DX
  847.          And AL,08h
  848.          Jnz A1
  849.       A2:
  850.          In AL,DX
  851.          And AL,08h
  852.          Jz A2
  853.       End;
  854.  
  855.       So, here you have it... A procedure to test the VBL. Now, the SetPalette
  856.     procedure should be like this:
  857.  
  858.       Procedure SetPalette(Pal:RgbList);
  859.       Var A:Byte;
  860.       Begin
  861.            WaitVBL;
  862.            For A:=0 To 255 do SetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
  863.       End;
  864.  
  865.       Easy, isn't it ?...
  866.  
  867.     ■ Palette effects
  868.  
  869.       Now, I will talk about two types of effects, and the application of one
  870.     of them. The palette by it's own is capable of some nice effects, as I think
  871.     I've shown in my Color Blind demo.
  872.  
  873.       ■ Rotations
  874.  
  875.         Rotating the palette is a good effect to start coding, and a very
  876.       effective one. Most of the effects in Color Blind are diferent types of
  877.       rotations.
  878.         Rotating the palette is just a matter of making color 0 be color 1,
  879.       color 1 be color 2, and so forth, until color 255 be color 0. You can also
  880.       do a reverse rotation, just by changing the direction. Code follows:
  881.  
  882.         Procedure RotatePal(Var Pal:RgbList);
  883.         Var Temp:RgbItem;
  884.             A:Byte;
  885.         Begin
  886.              Temp:=Pal[255];
  887.              For A:=254 DownTo 0 Do
  888.              Begin
  889.                   Pal[A+1]:=Pal[A];
  890.              End;
  891.              Pal[0]:=Temp;
  892.         End;
  893.  
  894.         Study this piece of code, I think it's very simple. This rotates the
  895.       colors of a palette buffer (type RgbList), not the colors of the screen.
  896.       After you rotate the buffer, you'd still have to set them, so you'll
  897.       notice the effect. It can be done with something like this:
  898.  
  899.         Var Pal1:RgbList;
  900.         .......
  901.         .......
  902.         GetPalette(Pal1);
  903.         Repeat
  904.               RotatePal(Pal1);
  905.               SetPalette(Pal1);
  906.         Until Keypressed;
  907.         .......
  908.         .......
  909.         .......
  910.  
  911.         This would rotate the palette of the screen until some key is pressed.
  912.         Now, let's move forth to a tougher effect:
  913.  
  914.       ■ Fades
  915.  
  916.         If you watch TV (and who doesn't ?), you'll see that most of the times,
  917.       the images don't just appear out of nowhere. They slowly fade in or out,
  918.       the colors slowly transforming to do the image. Well, it's fairly easy to
  919.       do so in the PC, and it is a bonus, because it's more impressive to see
  920.       the image slowly appearing than throwing it to the screen altogether.
  921.         The theory behind a fade is fairly simple. You have a source pallete
  922.       (usually the screen palette) and a target palette. Than, you compare
  923.       each color and increase or decrease their RGB values.
  924.         You compare the RGB values of color 0 of the source palette with the
  925.       RGB values of color 0 of target palette, and change their values in face
  926.       of that. The next piece of code was the first fade I've ever made, and it
  927.       is very badly done. It can be done a lot faster and prettier, but I leave
  928.       that to you.
  929.  
  930.         Procedure Fade(Target:RgbList);
  931.         Var Tmp:RgbList;
  932.             Flag:Boolean;
  933.             Loop:Integer;
  934.         Begin
  935.              Repeat
  936.                    Flag:=True;
  937.                    GetPalette(Tmp);
  938.                    For Loop:=0 To 255 Do
  939.                    Begin
  940.                         If Tmp[Loop].R>Target[Loop].R Then
  941.                         Begin
  942.                              Dec(Tmp[Loop].R);
  943.                              Flag:=False;
  944.                         End;
  945.                         If Tmp[Loop].G>Target[Loop].G Then
  946.                         Begin
  947.                              Dec(Tmp[Loop].G);
  948.                              Flag:=False;
  949.                         End;
  950.                         If Tmp[Loop].B>Target[Loop].B Then
  951.                         Begin
  952.                              Dec(Tmp[Loop].B);
  953.                              Flag:=False;
  954.                         End;
  955.                         If Tmp[Loop].R<Target[Loop].R Then
  956.                         Begin
  957.                              Inc(Tmp[Loop].R);
  958.                              Flag:=False;
  959.                         End;
  960.                         If Tmp[Loop].G<Target[Loop].G Then
  961.                         Begin
  962.                              Inc(Tmp[Loop].G);
  963.                              Flag:=False;
  964.                         End;
  965.                         If Tmp[Loop].B<Target[Loop].B Then
  966.                         Begin
  967.                              Inc(Tmp[Loop].B);
  968.                              Flag:=False;
  969.                         End;
  970.                    End;
  971.                    SetPalette(Tmp);
  972.              Until Flag;
  973.         End;
  974.  
  975.         This is very straighforward, and very simple. You just check all the
  976.       256 colors until they all reach their target counterpart. This procedure
  977.       can be expanded to allow speed control and other things like that, but
  978.       it works fine just as it is. For example, to fade out a screen (to fade
  979.       to black), you just set all colors in the target palette to 0 and then
  980.       fade the screen.
  981.         Now, we'll go on to discuss a pratical way to use the palette
  982.       rotations.
  983.  
  984.       ■ The static screen
  985.  
  986.         If you saw the Color Blind demo, you'll notice one of the last effects:
  987.       the static screen. This is a screen full of static (like if you tune the
  988.       TV to an unused station). This is simple to code, and impressive, never
  989.       the less, if coupled with some other effects, like a text scroll or a
  990.       fade in/out kind of stuff like in Color Blind.
  991.         To do a static screen, you must first define a pallete in which the
  992.       first 16 colors are greys, like this:
  993.  
  994.         Procedure SetGreys(Var Pal:RgbList);
  995.         Var A:Byte;
  996.         Begin
  997.              For A:=0 to 15 Do
  998.              Begin
  999.                   Pal[A].R:=A*4;
  1000.                   Pal[A].G:=A*4;
  1001.                   Pal[A].B:=A*4;
  1002.              End;
  1003.         End;
  1004.  
  1005.         Then, you fill the screen with the first 16 colors, using the Random
  1006.       function to maximaize the effect.
  1007.  
  1008.         Procedure FillScreen;
  1009.         Var X,Y:Integer;
  1010.         Begin
  1011.              For Y:=0 to 199 Do For X:=0 to 319 Do PutPixel(X,Y,Random(15));
  1012.         End;
  1013.  
  1014.         Finally, you cicle the 16 first colors. To do this, you'll have to
  1015.       change a bit the RotatePal procedure. It must be something like this:
  1016.  
  1017.         Procedure RotatePal(Var Pal:RgbList;First,Last:Byte);
  1018.         Var Temp:RgbItem;
  1019.             A:Byte;
  1020.         Begin
  1021.              Temp:=Pal[Last];
  1022.              For A:=Last-1 DownTo First Do
  1023.              Begin
  1024.                   Pal[A+1]:=Pal[A];
  1025.              End;
  1026.              Pal[First]:=Temp;
  1027.         End;
  1028.  
  1029.         To rotate the 16 first colors, you'll have to do something like this:
  1030.  
  1031.                   RotatePal(Pal1,0,15);
  1032.  
  1033.         I assume your palette buffer is called Pal1.
  1034.         So, here you have it... You personal untuned TV.
  1035.  
  1036.  
  1037.         Program Static_Screen;
  1038.  
  1039.         Uses Crt;
  1040.  
  1041.         Const VGA=$A000;
  1042.  
  1043.         Type RgbItem=Record
  1044.                            R,G,B:Byte;
  1045.                      End;
  1046.              RgbList=Array[0..255] of RgbItem;
  1047.  
  1048.         Var Pal1:RgbList;
  1049.  
  1050.         Procedure Initgraph; Assembler;
  1051.         Asm
  1052.            Mov AH,0
  1053.            Mov AL,13h
  1054.            Int 10h
  1055.         End;
  1056.  
  1057.         Procedure Closegraph; Assembler;
  1058.         Asm
  1059.            Mov AH,0
  1060.            Mov AL,03h
  1061.            Int 10h
  1062.         End;
  1063.  
  1064.         Procedure WaitVBL; Assembler;
  1065.         Label A1,A2;
  1066.         Asm
  1067.            Mov DX,3DAh
  1068.         A1:
  1069.            In AL,DX
  1070.            And AL,08h
  1071.            Jnz A1
  1072.         A2:
  1073.            In AL,DX
  1074.            And AL,08h
  1075.            Jz A2
  1076.         End;
  1077.  
  1078.         Procedure PutPixel(X,Y,C:Word);
  1079.         Begin
  1080.              Mem[VGA:(Y*320)+X]:=C;
  1081.         End;
  1082.  
  1083.         Procedure GetColor(Col:Byte;Var R,G,B:Byte);
  1084.         Begin
  1085.              Port[$3C7]:=Col;
  1086.              R:=Port[$3C9];
  1087.              G:=Port[$3C9];
  1088.              B:=Port[$3C9];
  1089.         End;
  1090.  
  1091.         Procedure SetColor(Col,R,B,G:Byte);
  1092.         Begin
  1093.              Port[$3C8]:=Col;
  1094.              Port[$3C9]:=R;
  1095.              Port[$3C9]:=G;
  1096.              Port[$3C9]:=B;
  1097.         End;
  1098.  
  1099.         Procedure GetPalette(Var Pal:RgbList);
  1100.         Var A:Byte;
  1101.         Begin
  1102.              For A:=0 To 255 do GetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
  1103.         End;
  1104.  
  1105.         Procedure SetPalette(Pal:RgbList);
  1106.         Var A:Byte;
  1107.         Begin
  1108.              WaitVBL;
  1109.              For A:=0 To 255 do SetColor(A,Pal[A].R,Pal[A].G,Pal[A].B);
  1110.         End;
  1111.  
  1112.         Procedure SetGreys(Var Pal:RgbList);
  1113.         Var A:Byte;
  1114.         Begin
  1115.              For A:=0 to 15 Do
  1116.              Begin
  1117.                   Pal[A+1].R:=A*4;
  1118.                   Pal[A+1].G:=A*4;
  1119.                   Pal[A+1].B:=A*4;
  1120.              End;
  1121.         End;
  1122.  
  1123.         Procedure SetBlack(Var Pal:RgbList);  { This sets the buffer to black }
  1124.         Var A:Byte;
  1125.         Begin
  1126.              For A:=0 to 255 Do
  1127.              Begin
  1128.                   Pal[A].R:=0;
  1129.                   Pal[A].G:=0;
  1130.                   Pal[A].B:=0;
  1131.              End;
  1132.         End;
  1133.  
  1134.         Procedure FillScreen;
  1135.         Var X,Y:Integer;
  1136.         Begin
  1137.              For Y:=0 to 199 Do For X:=0 to 319 Do PutPixel(X,Y,Random(15));
  1138.         End;
  1139.  
  1140.         Procedure RotatePal(Var Pal:RgbList;First,Last:Byte);
  1141.         Var Temp:RgbItem;
  1142.             A:Byte;
  1143.         Begin
  1144.              Temp:=Pal[Last];
  1145.              For A:=Last-1 DownTo First Do
  1146.              Begin
  1147.                   Pal[A+1]:=Pal[A];
  1148.              End;
  1149.              Pal[First]:=Temp;
  1150.         End;
  1151.  
  1152.         Procedure Fade(Target:RgbList);
  1153.         Var Tmp:RgbList;
  1154.             Flag:Boolean;
  1155.             Loop:Integer;
  1156.         Begin
  1157.              Repeat
  1158.                    Flag:=True;
  1159.                    GetPalette(Tmp);
  1160.                    For Loop:=0 To 255 Do
  1161.                    Begin
  1162.                         If Tmp[Loop].R>Target[Loop].R Then
  1163.                         Begin
  1164.                              Dec(Tmp[Loop].R);
  1165.                              Flag:=False;
  1166.                         End;
  1167.                         If Tmp[Loop].G>Target[Loop].G Then
  1168.                         Begin
  1169.                              Dec(Tmp[Loop].G);
  1170.                              Flag:=False;
  1171.                         End;
  1172.                         If Tmp[Loop].B>Target[Loop].B Then
  1173.                         Begin
  1174.                              Dec(Tmp[Loop].B);
  1175.                              Flag:=False;
  1176.                         End;
  1177.                         If Tmp[Loop].R<Target[Loop].R Then
  1178.                         Begin
  1179.                              Inc(Tmp[Loop].R);
  1180.                              Flag:=False;
  1181.                         End;
  1182.                         If Tmp[Loop].G<Target[Loop].G Then
  1183.                         Begin
  1184.                              Inc(Tmp[Loop].G);
  1185.                              Flag:=False;
  1186.                         End;
  1187.                         If Tmp[Loop].B<Target[Loop].B Then
  1188.                         Begin
  1189.                              Inc(Tmp[Loop].B);
  1190.                              Flag:=False;
  1191.                         End;
  1192.                    End;
  1193.                    SetPalette(Tmp);
  1194.              Until Flag;
  1195.         End;
  1196.  
  1197.         Begin
  1198.              Initgraph;
  1199.              SetBlack(Pal1);
  1200.              SetPalette(Pal1);
  1201.              FillScreen;
  1202.              SetGreys(Pal1);
  1203.              Fade(Pal1);
  1204.              Repeat
  1205.                    RotatePal(Pal1,1,16);
  1206.                    SetPalette(Pal1);
  1207.              Until KeyPressed;
  1208.              SetBlack(Pal1);
  1209.              Fade(Pal1);
  1210.              Closegraph;
  1211.              Writeln('Another SpellCaster production... The Static Screen...');
  1212.              Writeln('Press RETURN to quit...');
  1213.              Readln;
  1214.         End.
  1215.  
  1216.       So, here you have it... The Static Screen. I like this effect very much.
  1217.     I was to include also a part about the cross-fade effect, but it's a lot
  1218.     more complicated and requires other knowledge. As soon as I feel you're
  1219.     ready, I'll make a tutor on it too.
  1220.  
  1221.  
  1222.  
  1223. ■ Points of view
  1224.  
  1225.     Well, I have bad news for all fans out there... I'm going to start school
  1226.   tomorrow, so, I think the next issue of 'The Mag' will be slightly delayed,
  1227.   because I'm moving to a new scholl that's almost 50 km from where I live, and
  1228.   I don't know anything nor anyone there, so I don't think I can prepare the
  1229.   next issue in time... But don't worry, I'll still be making the magazine, for
  1230.   all coders and would-be coders out there.
  1231.     I also don't have time because I'm going to start coding a new game...
  1232.   I don't know the name for it, nor the kind of game it will be, but I have some
  1233.   ideas. If you would like to make a sugestion, feel free to write. I need input
  1234.   from all of you out there on what kind of game is the favourite amongst you.
  1235.     I was writing a game, called "Titans", a strategy wargame, but because of
  1236.   my insane ambition, I can't do it without learning first how to work with
  1237.   Extended and Expanded memory. If anyone out there knows, type me a letter.
  1238.     So, I think this is goodbye... I think this was a great issue, with assembly
  1239.   and other stuff in it. If you think so too, write to me and say something.
  1240.  
  1241.  
  1242.  
  1243. ■ The adventures of Spellcaster, the rebel programmer of the year 2018.
  1244.  
  1245.   Episode 3 - Escape
  1246.  
  1247.     Everything is set now. After one month of pure disgust, I'ver learned to
  1248.   program the Atari, at least enough to make a virus powerfull enough to disable
  1249.   the prison's power grid. I've just finished my chores, so I can go now to the
  1250.   computer center and activate the virus.
  1251.     I walked slowly, fearing that some guard noticed my thoughts, and prevented
  1252.   my long-awayted freedom. I walked until the room. The guard in the door
  1253.   looked at me, as if it could read my mind, and smilled with a grin, making me
  1254.   a signal to enter. I went inside the gloomy room. It was cold and dark, only
  1255.   the brightness of the monitors to lighten it up. There it was... The Atari
  1256.   520ST, with it's patetic 32 color display. I sat down at the keyboard and
  1257.   closed my eyes. It was still hard for me to look at that disgusting thing. I
  1258.   typed away, and an half-hour later, everything was done. I prepared the virus
  1259.   to go active at two o'clock in the morning. Then, I returned to my chambers,
  1260.   where I lyed down, with my eyes open. At 11:00, the lazer bars were activated
  1261.   and the lights were turned off. I looked at the entry to my cell, staring at
  1262.   the red light that crossed it, knowing that this was probably the last time
  1263.   I would see them.
  1264.     At precisely 2:00, the red light went off. Seconds later, I got up and
  1265.   started walking quitly by the walkway, trying to make no noise. I felt someone
  1266.   breathing in my neck, I turned my head and I saw that I was beeing followed.
  1267.   The other inmates also noticed the power shortage. Suddently, lazer shots were
  1268.   heard, and screams raised all around. The guards noticed us and were firing.
  1269.   I start running, followed by another convict, and I knocked a guard over,
  1270.   jumping over him and punching him until he was dead... I didn't had conscience
  1271.   problems... I got up and continued running. In a few minutes, I was out of the
  1272.   prison's gates, and I suddently stopped. The taste of freedom filled my mouth,
  1273.   when I was knocked over by someone, followed by a stream of lazer shots, that
  1274.   hitted the ground where I stood. The person that was now on top of me saved my
  1275.   life! I pushed him of me, then got up, helping the other man getting up. It was
  1276.   a tall, blond man, that smilled at me. I looked at him and smilled back. Then,
  1277.   we both started running, as there was no tomorrow, until we could run no more.
  1278.   I drop down to my knees and looked back. At some distance, I could still hear
  1279.   screams and lazer shots of the Atari Penetenciary. Then, I noticed that the
  1280.   tall man was still behind me, looking forward. I looked forward and saw the
  1281.   Atlantic Ocean right in front of me. Then I yelled, as loud as I could:
  1282.   - I'M FREE !!!!!!!
  1283.  
  1284.  
  1285.                                          See you in the next issue
  1286.                                         Diogo "SpellCaster" Andrade
  1287.